﻿using System;
using System.Data;
using NMock2;

namespace NMock3.Tests
{
	[NUnit.Framework.TestFixture]
	public class MessageGrabberTests
	{
		private MockFactory factory = new MockFactory();
		private Mock<Iam2Bmocked> _mock;
		private Driver _driver;

		[NUnit.Framework.SetUp]
		public void TestInit()
		{
			_mock = factory.CreateMock<Iam2Bmocked>();
			_driver = new Driver(_mock.MockObject);
		}

		[NUnit.Framework.TearDown]
		public void TestClean()
		{
			factory.VerifyAllExpectationsHaveBeenMet();
		}

		[NUnit.Framework.Test]
		public void ReturnVoidTest()
		{
			_mock.Expects.One.MethodWith(m => m.ReturnVoid("value"));

			_driver.Go("void", "value");

			NUnit.Framework.Assert.IsTrue(true);
		}

		[NUnit.Framework.Test]
		public void ReturnBoolTest()
		{
			_mock.Expects.One.MethodWith(m => m.ReturnBool("value")).Will(Return.Value(true));
			_mock.Expects.One.MethodWith(m => m.ReturnBool("value")).WillReturn(true);

			_driver.Go("bool", "value");
			_driver.Go("bool", "value");

			NUnit.Framework.Assert.IsTrue(true);
		}

		[NUnit.Framework.Test]
		public void ReturnStringTest()
		{
			_mock.Expects.One.MethodWith(m => m.ReturnString("value")).Will(Return.Value("hello"));
			_mock.Expects.One.MethodWith(m => m.ReturnString("value")).WillReturn("hello");

			_driver.Go("string", "value");
			_driver.Go("string", "value");

			NUnit.Framework.Assert.IsTrue(true);
		}

		[NUnit.Framework.Test]
		public void ReturnIntTest()
		{
			_mock.Expects.One.MethodWith(m => m.ReturnInt("value")).Will(Return.Value(3));
			_mock.Expects.One.MethodWith(m => m.ReturnInt("value")).WillReturn(3);

			_driver.Go("int", "value");
			_driver.Go("int", "value");

			NUnit.Framework.Assert.IsTrue(true);
		}

		[NUnit.Framework.Test]
		public void ReturnEnumTest()
		{
			_mock.Expects.One.MethodWith(m => m.ReturnEnum("value")).Will(Return.Value(TestValues.Second));
			_mock.Expects.One.MethodWith(m => m.ReturnEnum("value")).WillReturn(TestValues.Second);

			_driver.Go("enum", "value");
			_driver.Go("enum", "value");

			NUnit.Framework.Assert.IsTrue(true);
		}

		[NUnit.Framework.Test]
		public void ReturnInterfaceTest()
		{
			_mock.Expects.One.MethodWith(m => m.ReturnInterface("value")).Will(Return.Value(new ReturnValue()));
			_mock.Expects.One.MethodWith(m => m.ReturnInterface("value")).WillReturn(new ReturnValue());

			_driver.Go("interface", "value");
			_driver.Go("interface", "value");

			NUnit.Framework.Assert.IsTrue(true);
		}

		[NUnit.Framework.Test]
		public void ReturnStructTest()
		{
			_mock.Expects.One.MethodWith(m => m.ReturnStruct("value")).Will(Return.Value(new TestStruct()));
			_mock.Expects.One.MethodWith(m => m.ReturnStruct("value")).WillReturn(new TestStruct());

			_driver.Go("struct", "value");
			_driver.Go("struct", "value");

			NUnit.Framework.Assert.IsTrue(true);
		}

		[NUnit.Framework.Test]
		public void ReturnArrayTest()
		{
			_mock.Expects.One.MethodWith(m => m.ReturnArray("value")).Will(Return.Value(new int[] { }));
			_mock.Expects.One.MethodWith(m => m.ReturnArray("value")).WillReturn(new int[] { });

			_driver.Go("array", "value");
			_driver.Go("array", "value");

			NUnit.Framework.Assert.IsTrue(true);
		}

		[NUnit.Framework.Test]
		public void ReturnObjectTest()
		{
			_mock.Expects.One.MethodWith(m => m.ReturnObject("value")).Will(Return.Value(new object()));
			_mock.Expects.One.MethodWith(m => m.ReturnObject("value")).WillReturn(new object());

			_driver.Go("object", "value");
			_driver.Go("object", "value");

			NUnit.Framework.Assert.IsTrue(true);
		}
	}

	public interface Iam2Bmocked
	{
		void ReturnVoid(string s);
		bool ReturnBool(string s);
		string ReturnString(string s);
		int ReturnInt(string s);
		TestValues ReturnEnum(string s);
		IamAreturnValue ReturnInterface(string s);
		TestStruct ReturnStruct(string s);
		int[] ReturnArray(string s);
		object ReturnObject(string s);


		string Read { get; }
		string Write { set; }
		string ReadWrite { get; set; }

		DataSet ReadObject { get; }
		DataSet WriteObject { set; }
		DataSet ReadWriteObject { get; set; }

		string this[int index] { get; set; }
		string this[string name] { get; }
		string this[Guid id] { get; }
		string this[Type type] { get; }

		//string Item { get; set; }//I am so glad this is a compiler error!!

		//string this[int idx1, int idx2] { get; set; } //evil >:-<
	}

	public class Driver
	{
		private Iam2Bmocked _mock;

		public Driver(Iam2Bmocked mock)
		{
			_mock = mock;
		}

		public void Go(string method, string parameter)
		{
			switch(method)
			{
				case "void":
					_mock.ReturnVoid(parameter);
					break;
				case "bool":
					_mock.ReturnBool(parameter);
					break;
				case "string":
					_mock.ReturnString(parameter);
					break;
				case "int":
					_mock.ReturnInt(parameter);
					break;
				case "enum":
					_mock.ReturnEnum(parameter);
					break;
				case "interface":
					_mock.ReturnInterface(parameter);
					break;
				case "struct":
					_mock.ReturnStruct(parameter);
					break;
				case "array":
					_mock.ReturnArray(parameter);
					break;
				case "object":
					_mock.ReturnObject(parameter);
					break;
			}
		}

		public void SetWrite(string value)
		{
			_mock.Write = value;
		}

		public string GetRead()
		{
			return _mock.Read;
		}

		public void SetReadWrite(string value)
		{
			_mock.ReadWrite = value;
		}

		public string GetReadWrite()
		{
			return _mock.ReadWrite;
		}
	}

	public enum TestValues
	{
		None = 0,
		First = 1,
		Second = 2,
	}

	public struct TestStruct
	{
		public int X;
		public int Y;
	}

	public interface IamAreturnValue
	{
		void SayHi();
	}

	public class ReturnValue : IamAreturnValue
	{
		#region Implementation of IamAreturnValue

		public void SayHi()
		{
			throw new NotImplementedException();
		}

		#endregion
	}
}
